package com.aleyn.router

import android.content.Context
import android.content.Intent
import androidx.annotation.Keep
import com.aleyn.router.core.LRouterInterceptor
import com.aleyn.router.core.NavCallback
import com.aleyn.router.core.Navigator
import com.aleyn.router.core.RouteMeta
import com.aleyn.router.core.RouterController
import com.aleyn.router.core.RouterUrl
import com.aleyn.router.core.getRouterKey
import com.aleyn.router.data.InterceptorData
import com.aleyn.router.inject.Core
import com.aleyn.router.inject.qualifier.Qualifier
import com.aleyn.router.util.ILogger
import com.aleyn.router.util.currentLogger
import com.aleyn.router.util.dLog
import com.aleyn.router.util.getApplicationByReflect
import com.aleyn.router.util.openLog
import java.util.concurrent.ThreadPoolExecutor
import kotlin.reflect.KClass

/**
 * @author: Aleyn
 * @date: 2023/6/9 11:02
 */

/**
 * 全局 ApplicationContext
 */
private var applicationContext: Context? = null

/**
 * 获取全局 ApplicationContext，如果为空则通过反射获取。
 */
val appContext
    get() = applicationContext ?: getApplicationByReflect().also {
        applicationContext = it
    }

/**
 * LRouter 路由框架的核心入口类。
 * 提供了框架的初始化、配置、路由注册、导航、依赖注入等所有核心功能。
 */
@Keep
object LRouter {

    /**
     * 是否启用自动初始化。默认为 `true`。
     * 如果禁用，则需要手动调用 [init] 方法。
     */
    var enabledAutoInit = true

    /**
     * 初始化完成的标志位，防止重复初始化。
     */
    private var isInit = false

    /**
     * 设置日志打印的开关。
     *
     * @param status `true` 开启日志, `false` 关闭日志。
     */
    @JvmStatic
    fun setLogSwitch(status: Boolean) {
        openLog = status
    }

    /**
     * 自定义线程池，用于处理异步任务，例如预加载。
     *
     * @param tpe 自定义的线程池实例。
     */
    @JvmStatic
    fun setExecutor(tpe: ThreadPoolExecutor?) {
        RouterController.setThreadPoolExecutor(tpe)
    }


    /**
     * 自定义日志记录器，用于替换默认的 Logcat 输出。
     *
     * @param logger 实现 [ILogger] 接口的日志记录器实例。
     */
    @JvmStatic
    fun setLogger(logger: ILogger) {
        currentLogger = logger
    }


    /**
     * 手动注册一个路由元数据。
     * 通常情况下，路由表由 KSP 自动生成和注册，此方法用于动态添加路由。
     *
     * @param routeMeta 路由元数据实例。
     */
    @JvmStatic
    fun registerRoute(routeMeta: RouteMeta) {
        val key = routeMeta.path.getRouterKey()
        "registerRoute : $key".dLog()
        RouterController.ROUTER_MAP[key] = routeMeta
    }

    /**
     * 根据 [RouterUrl] 获取对应的路由元数据。
     *
     * @param routerUrl 路由地址的封装对象。
     * @return 如果找到，则返回 [RouteMeta]，否则返回 `null`。
     */
    @JvmStatic
    fun getRouteMeta(routerUrl: RouterUrl?): RouteMeta? {
        val path = routerUrl?.routerKey.orEmpty()
        return RouterController.ROUTER_MAP[path]
    }

    /**
     * 添加全局拦截器。
     *
     * @param priority 拦截器的优先级，数值越小，优先级越高。
     * @param interceptor 拦截器实例。
     */
    @JvmStatic
    fun addInterceptor(priority: Byte, interceptor: LRouterInterceptor) {
        RouterController.routerInterceptors.add(InterceptorData(priority, interceptor))
    }

    /**
     * 设置全局的导航回调。
     * 如果某次导航单独设置了回调，则全局回调不会被执行。
     * 单独设置的回调优先级更高。
     *
     * @param navCallback 全局导航回调实例。
     */
    @JvmStatic
    fun setNavCallback(navCallback: NavCallback) {
        RouterController.navCallback = navCallback
    }

    /**
     * 初始化 LRouter 框架。
     * 此方法会加载由 KSP 生成的路由表和依赖注入模块。
     *
     * @param context ApplicationContext，用于初始化和后续操作。
     */
    @JvmStatic
    fun init(context: Context?) {
        applicationContext = context?.applicationContext
        if (isInit) return
        "init: start".dLog()
        RouterController.init(applicationContext!!)
        isInit = true
    }

    /**
     * 构建一个导航请求。
     *
     * @param url 目标页面的路由地址。
     * @param intent 可选的 Intent，用于传递复杂的参数或设置标志位。
     * @return 返回一个 [Navigator] 实例，可以链式调用配置导航参数。
     */
    @JvmStatic
    fun build(url: String?, intent: Intent? = null) = Navigator.navBuilder(url, intent)

    /**
     * 为目标对象中所有被 `@Autowired` 注解的属性进行依赖注入。
     *
     * @param target 需要注入属性的目标对象，通常是 Activity 或 Fragment。
     */
    @JvmStatic
    fun inject(target: Any?) {
        RouterController.routerGenerate.injectAutowired(target)
    }

    /**
     * 从依赖注入容器中获取一个实例 (Kotlin)。
     *
     * @param T 实例的类型。
     * @param clazz 实例的 KClass。
     * @param qualifier 可选的限定符，用于区分同一类型的不同实例。
     * @return 返回获取到的实例，如果找不到则返回 `null`。
     */
    @JvmStatic
    fun <T> get(clazz: KClass<*>, qualifier: Qualifier? = null): T? {
        return Core.getOrNull(clazz, qualifier)
    }

    /**
     * 从依赖注入容器中获取一个实例 (Kotlin reified)。
     *
     * @param T 实例的类型。
     * @param qualifier 可选的限定符。
     * @return 返回获取到的实例，如果找不到则返回 `null`。
     */
    inline fun <reified T> getByType(qualifier: Qualifier? = null): T? {
        return Core.getOrNull(T::class, qualifier)
    }

    /**
     * 从依赖注入容器中获取一个实例 (Java)。
     *
     * @param T 实例的类型。
     * @param clazz 实例的 Class。
     * @param qualifier 可选的限定符。
     * @return 返回获取到的实例，如果找不到则返回 `null`。
     */
    @JvmStatic
    fun <T> getByJava(clazz: Class<*>, qualifier: Qualifier?): T? {
        return Core.getOrNull(clazz.kotlin, qualifier)
    }

    /**
     * 从依赖注入容器中获取一个实例 (Java, 无限定符)。
     *
     * @param T 实例的类型。
     * @param clazz 实例的 Class。
     * @return 返回获取到的实例，如果找不到则返回 `null`。
     */
    @JvmStatic
    fun <T> getByJava(clazz: Class<*>): T? {
        return Core.getOrNull(clazz.kotlin, null)
    }

}